//
//  BMSKeychain.m
//  BMSSDK
//
//  Created by YeJary on 2025/5/12.
//

#import "BMSKeychain.h"
#import "BMSNSLog.h"
#import <Security/Security.h>

static NSString *splashKeychainService = @"";
static NSString *splashKeychainAccountId = @"";

static NSString *keychainService  = @"WDkeychainService";
static NSString *keychainUUID     = @"WDkeychainUUID";

@interface BMSKeychain()


@end

@implementation BMSKeychain

//创建kechain 属性 kSecAttrService，kSecAttrAccount 标志一个item
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service accountId:(NSString *)accountId {
    return [NSMutableDictionary dictionaryWithObjectsAndKeys:
            (id)kSecClassGenericPassword,(id)kSecClass,//类型
            service, (id)kSecAttrService,//服务
            accountId, (id)kSecAttrAccount,//帐户
            (id)kSecAttrAccessibleAlwaysThisDeviceOnly,(id)kSecAttrAccessible,//访问的类型
            nil];
}

+ (NSString *)WDKeychainGetSplashOpenStatus
{
    id ret = nil;
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:splashKeychainService accountId:splashKeychainAccountId];
    //查询的返回类型
    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
    //返回的数目
    [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
    CFDataRef keyData = NULL;
    if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
        @try {
            ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
        } @catch (NSException *e) {
            WDBMSLog(@"Unarchive of %@ failed: %@", keychainService, e);
        } @finally {
        }
    }
    if (keyData)
        CFRelease(keyData);
    if (ret)
    {
        return ret;
    }
    return ret;
}

+ (void)WDKeychainSaveSplashOpenStatus:(NSString *)status
{
    //创建查询支点
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:splashKeychainService accountId:splashKeychainAccountId];
    //创建新的 item 前先删除旧的 item
    SecItemDelete((CFDictionaryRef)keychainQuery);
    //先把需要存储的数据序列化，
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:status] forKey:(id)kSecValueData];
    //创建新的 item 到keychain
    SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
}

+ (NSString *)WDKeychainGetUUID
{
    id ret = nil;
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:keychainService accountId:keychainUUID];
    //查询的返回类型
    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
    //返回的数目
    [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
    CFDataRef keyData = NULL;
    if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
        @try {
            ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
        } @catch (NSException *e) {
            WDBMSLog(@"Unarchive of %@ failed: %@", keychainService, e);
        } @finally {
        }
    }
    if (keyData)
        CFRelease(keyData);
    if (ret)
    {
        return ret;
    }else{
        NSString *uuid = [[NSUUID UUID] UUIDString];
        [self WDKeychainSaveUUID:uuid];
        return uuid;
    }
    return ret;
}

+ (void)WDKeychainSaveUUID:(NSString *)uuid
{
    //创建查询支点
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:keychainService accountId:keychainUUID];
    //创建新的 item 前先删除旧的 item
    SecItemDelete((CFDictionaryRef)keychainQuery);
    //先把需要存储的数据序列化，
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:uuid] forKey:(id)kSecValueData];
    //创建新的 item 到keychain
    SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
}



+ (NSMutableDictionary *)keychainDicWithAccountId:(NSString *)accountId andServiceId:(NSString *)serviceId{
//构建一个存取条件,实质是一个字典
    NSString *classKey = (__bridge NSString *)kSecClass;
    //指定服务类型是普通密码
    NSString *classValue = (__bridge NSString *)kSecClassGenericPassword;
    NSString *accessibleKey = (__bridge NSString *)kSecAttrAccessible;
    //指定安全类型是任何时候都可以访问
    NSString *accessibleValue = (__bridge NSString *)kSecAttrAccessibleAlways;
    NSString *accountKey = (__bridge NSString *)kSecAttrAccount;
    //指定服务的账户名 可以与服务名相同 账户名可以对应多个服务名
    NSString *accountValue = accountId;
    NSString *serviceKey = (__bridge NSString *)kSecAttrService;
    //指定服务的名字 可以与服务账户名相同
    NSString *serviceValue = serviceId;
    NSDictionary *keychainItems = @{classKey      : classValue,
                                    accessibleKey : accessibleValue,
                                    accountKey    : accountValue,
                                    serviceKey    : serviceValue};
    return keychainItems.mutableCopy;
}

+ (BOOL)keychainSaveData:(id)aData withAccountIdentifier:(NSString *)accountId andServiceIdentifier:(NSString *)serviceId{
    // 获取存储的数据的条件
    NSMutableDictionary *saveQueryDic = [self keychainDicWithAccountId:accountId andServiceId:serviceId];
    // 删除旧的数据
    SecItemDelete((CFDictionaryRef)saveQueryDic);
    // 设置新的数据
    [saveQueryDic setObject:[NSKeyedArchiver archivedDataWithRootObject:aData] forKey:(id)kSecValueData];
    // 添加数据
    OSStatus saveState = SecItemAdd((CFDictionaryRef)saveQueryDic, nil);
    // 释放对象
    saveQueryDic = nil ;
    // 判断是否存储成功
    if (saveState == errSecSuccess) {
        return YES;
    }
    return NO;
}

+ (id)keychainGetDataWithAccountIdentifier:(NSString *)accountId andServiceIdentifier:(NSString *)serviceId{
    id idObject = nil ;
    // 通过标记获取数据查询条件
    NSMutableDictionary * readQueryDic = [self keychainDicWithAccountId:accountId andServiceId:serviceId];
    // 查询结果返回到 kSecValueData (此项必选)
    [readQueryDic setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
    // 只返回搜索到的第一条数据 (此项必选)
    [readQueryDic setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
    // 创建一个对象接受结果
    CFDataRef keyChainData = nil ;
    // 通过条件查询数据
    if (SecItemCopyMatching((CFDictionaryRef)readQueryDic , (CFTypeRef *)&keyChainData) == noErr){
        @try {
            //转换类型
            idObject = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)(keyChainData)];
        } @catch (NSException * exception){
            WDBMSLog(@"Unarchive of search data where %@ failed of %@ ",serviceId,exception);
        }
    }
    if (keyChainData) {
        CFRelease(keyChainData);
    }
    readQueryDic = nil;
    // 返回数据
    return idObject ;
}

@end
